package gui;
import java.awt.EventQueue;

import javax.swing.JFrame;
import java.awt.GridLayout;
import javax.swing.JPanel;

import java.awt.Color;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.KeyStroke;

import java.awt.FlowLayout;
import javax.swing.table.DefaultTableModel;
import javax.swing.JMenuBar;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

import javax.swing.JMenu;
import javax.swing.JMenuItem;

import javax.swing.JScrollPane;

import logic.FileSystemFactory;
import logic.UnsupportedProtocol;
import logic.file.IDirectory;
import logic.file.IFile;
import logic.operation.DeleteOperation;

import javax.swing.JToolBar;


//TODO eksternalizacja Stringów
//TODO TC pokazuje ikone pliku na podstawie najprawdop. zapisów w rejestrze windowsowym
//TODO szybkie zmienianie okna jakiejkolwiek własnej aplikacji w javie powoduje występowanie "czarnej ramki", w przypadku "normalnych appsów" to nie występuje?!?!?!
//problem występuje tylko w przypadku Swinga 
//jtoolbar zamiast loznych buttonow + podzial okna na 2 jsplipane
//D&D, java nio
//TODO przelaczanie dyskow
//TODO konfigurowanie okan oczywiscie przed jego wyswietleniem
public class MyTC {
	
	static Logger logger = Logger.getLogger(MyTC.class.getName());

	private JFrame frame;
	private JTable rightTable;
	private JTable leftTable;
	private JTextField addrTextFLeft;
	private String currentPathLeft;
	private String currentPathRight;
	private JTextField addrTextFRight;
	private JSplitPane splitPane;
	
	private Action goToAddressActionLeft = new GoToAddressActionLeft();
	private Action goToAddressActionRight = new GoToAddressActionRight();
	private MouseListener tableMouseListener = new TableMouseListener();
	private Action enterPressed = new EnterPressedAction();
	private Action spacePressed = new SpacePressedAction();
	/**
	 * Create the application.
	 */
	public MyTC() {
		initialize();
		frame.setVisible(true);
		initializeComponentsValues();
		loadConfiguration();
	}

	private void loadConfiguration() {
		// TODO Auto-generated method stub
		
	}

	private void initializeComponentsValues() {
		// TODO Auto-generated method stub
		
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(100, 100, 889, 391);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(new GridLayout(1, 2, 0, 0));

		////////////////////////////////LEFT PANEL/////////////////////////////////////////
		///////////////////////////////////////////////////////////////////////////////////
		JPanel panelLeft = new JPanel();
		frame.getContentPane().add(panelLeft);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{395};
		gbl_panel.rowHeights = new int[]{20, 27, 321, 0};
		gbl_panel.columnWeights = new double[]{1.0};
		gbl_panel.rowWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE};
		panelLeft.setLayout(gbl_panel);
		
		JPanel btnPanelLeft = new JPanel();
		GridBagConstraints gbc_btnPanelLeft = new GridBagConstraints();
		gbc_btnPanelLeft.fill = GridBagConstraints.BOTH;
		gbc_btnPanelLeft.insets = new Insets(0, 0, 5, 5);
		gbc_btnPanelLeft.gridx = 0;
		gbc_btnPanelLeft.gridy = 0;
		panelLeft.add(btnPanelLeft, gbc_btnPanelLeft);
		btnPanelLeft.setLayout(new GridLayout(0, 4, 0, 0));
		
		JToolBar toolBar = new JToolBar();
		btnPanelLeft.add(toolBar);
		
		JButton btnLeft = new JButton("DEL");
		btnLeft.addActionListener(new DeletingAction());
		toolBar.add(btnLeft);
		
		JButton btnLeft1 = new JButton("bl1");
		toolBar.add(btnLeft1);
		
		JPanel addrPanelLeft = new JPanel();
		GridBagConstraints gbc_addrPanelLeft = new GridBagConstraints();
		gbc_addrPanelLeft.fill = GridBagConstraints.BOTH;
		gbc_addrPanelLeft.insets = new Insets(0, 0, 5, 5);
		gbc_addrPanelLeft.gridx = 0;
		gbc_addrPanelLeft.gridy = 1;
		panelLeft.add(addrPanelLeft, gbc_addrPanelLeft);
		GridBagLayout gbl_addrPanelLeft = new GridBagLayout();
		gbl_addrPanelLeft.columnWidths = new int[]{38, 390, 30};
		gbl_addrPanelLeft.rowHeights = new int[]{22, 0};
		gbl_addrPanelLeft.columnWeights = new double[]{1.0, 1.0, Double.MIN_VALUE};
		gbl_addrPanelLeft.rowWeights = new double[]{0.0, Double.MIN_VALUE};
		addrPanelLeft.setLayout(gbl_addrPanelLeft);
		
		String []  strT = {"1","2","3"};
		JComboBox diskList = new JComboBox(strT );
		//addrTextFLeft.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "EnterPressed");
		//addrTextFLeft.getActionMap().put("EnterPressed", goToAddressActionLeft);
		diskList.addMouseListener(null);
		GridBagConstraints gbc_diskList = new GridBagConstraints();
		gbc_diskList.insets = new Insets(0, 0, 0, 5);
		gbc_diskList.fill = GridBagConstraints.BOTH;
		gbc_diskList.gridx = 0;
		gbc_diskList.gridy = 0;
		addrPanelLeft.add(diskList, gbc_diskList);
		
		addrTextFLeft = new JTextField();
		//addrTextFLeft.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("ENTER"), "EnterPressed");
		//addrTextFLeft.getActionMap().put("EnterPressed", goToAddressActionLeft);
		addrTextFLeft.addActionListener(goToAddressActionLeft);
		GridBagConstraints gbc_addrTextFLeft = new GridBagConstraints();
		gbc_addrTextFLeft.insets = new Insets(0, 0, 0, 5);
		gbc_addrTextFLeft.fill = GridBagConstraints.BOTH;
		gbc_addrTextFLeft.gridx = 1;
		gbc_addrTextFLeft.gridy = 0;
		addrPanelLeft.add(addrTextFLeft, gbc_addrTextFLeft);
		
		JButton btnGoLeft = new JButton("GO");
		btnGoLeft.addActionListener(goToAddressActionLeft);
		GridBagConstraints gbc_btnGoLeft = new GridBagConstraints();
		gbc_btnGoLeft.gridx = 2;
		gbc_btnGoLeft.gridy = 0;
		addrPanelLeft.add(btnGoLeft, gbc_btnGoLeft);
		
		JScrollPane scrollPaneLeft = new JScrollPane();
		GridBagConstraints gbc_scrollPaneLeft = new GridBagConstraints();
		gbc_scrollPaneLeft.fill = GridBagConstraints.BOTH;
		gbc_scrollPaneLeft.insets = new Insets(0, 0, 0, 5);
		gbc_scrollPaneLeft.gridx = 0;
		gbc_scrollPaneLeft.gridy = 2;
		panelLeft.add(scrollPaneLeft, gbc_scrollPaneLeft);
		
		leftTable = new JTable(new FilesTableModel(null, new String[]{"Nazwa", "Typ", "Wielkość", "Data mod.", "Atrybuty"}));
		leftTable.getColumn("Nazwa").setCellRenderer(new FileNameCellRenderer());
		leftTable.setShowGrid(false);
		//leftTable.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "EnterPressed");
		//leftTable.getActionMap().put("EnterPressed", enterPressed);
		scrollPaneLeft.setViewportView(leftTable);
		
		//////////////////////////RIGHT TABLE////////////////////////////////////////////////
		////////////////////////////////////////////////////////////////////////////////////
		JPanel panelRight = new JPanel();
		frame.getContentPane().add(panelLeft);
		GridBagLayout gbl_panel1 = new GridBagLayout();
		gbl_panel1.columnWidths = new int[]{395};
		gbl_panel1.rowHeights = new int[]{20, 27, 321, 0};
		gbl_panel1.columnWeights = new double[]{1.0};
		gbl_panel1.rowWeights = new double[]{0.0, 0.0, 1.0, Double.MIN_VALUE};
		panelRight.setLayout(gbl_panel1);
		
		JPanel btnPanelRight = new JPanel();
		GridBagConstraints gbc_btnPanelRight = new GridBagConstraints();
		gbc_btnPanelRight.fill = GridBagConstraints.BOTH;
		gbc_btnPanelRight.insets = new Insets(0, 0, 5, 5);
		gbc_btnPanelRight.gridx = 0;
		gbc_btnPanelRight.gridy = 0;
		panelRight.add(btnPanelRight, gbc_btnPanelRight);
		btnPanelRight.setLayout(new GridLayout(0, 4, 0, 0));
		
		JToolBar toolBar_1 = new JToolBar();
		btnPanelRight.add(toolBar_1);
		
		JButton btnRight = new JButton("b");
		btnRight.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
			}
		});
		toolBar_1.add(btnRight);
		
		JButton btn1Right = new JButton("b1");
		toolBar_1.add(btn1Right);
		
		JPanel addrPanelRight = new JPanel();
		GridBagConstraints gbc_addrPanelRight = new GridBagConstraints();
		gbc_addrPanelRight.fill = GridBagConstraints.BOTH;
		gbc_addrPanelRight.insets = new Insets(0, 0, 5, 5);
		gbc_addrPanelRight.gridx = 0;
		gbc_addrPanelRight.gridy = 1;
		panelRight.add(addrPanelRight, gbc_addrPanelRight);
		GridBagLayout gbl_addrPanelRight = new GridBagLayout();
		gbl_addrPanelRight.columnWidths = new int[]{390, 0, 0};
		gbl_addrPanelRight.rowHeights = new int[]{22, 0};
		gbl_addrPanelRight.columnWeights = new double[]{1.0, 0.0, Double.MIN_VALUE};
		gbl_addrPanelRight.rowWeights = new double[]{0.0, Double.MIN_VALUE};
		addrPanelRight.setLayout(gbl_addrPanelRight);
		
		addrTextFRight = new JTextField();
		//addrTextFRight.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ENTER"), "EnterPressed");
		//addrTextFRight.getActionMap().put("EnterPressed", goToAddressActionRight);
		addrTextFRight.addActionListener(goToAddressActionRight);	//ENTER na polu tekstowym wowoluje actionPerformed z actionListenera
		GridBagConstraints gbc_addrTextFRight = new GridBagConstraints();
		gbc_addrTextFRight.insets = new Insets(0, 0, 0, 5);
		gbc_addrTextFRight.fill = GridBagConstraints.BOTH;
		gbc_addrTextFRight.gridx = 0;
		gbc_addrTextFRight.gridy = 0;
		addrPanelRight.add(addrTextFRight, gbc_addrTextFRight);
		
		JButton btnGoRight = new JButton("GO");
		btnGoRight.addActionListener(goToAddressActionRight);
		GridBagConstraints gbc_btnGoRight = new GridBagConstraints();
		gbc_btnGoRight.gridx = 1;
		gbc_btnGoRight.gridy = 0;
		addrPanelRight.add(btnGoRight, gbc_btnGoRight);
		
		JScrollPane scrollPaneRight = new JScrollPane();
		GridBagConstraints gbc_scrollPaneRight = new GridBagConstraints();
		gbc_scrollPaneRight.fill = GridBagConstraints.BOTH;
		gbc_scrollPaneRight.insets = new Insets(0, 0, 0, 5);
		gbc_scrollPaneRight.gridx = 0;
		gbc_scrollPaneRight.gridy = 2;
		panelRight.add(scrollPaneRight, gbc_scrollPaneRight);
		
		rightTable = new JTable(new FilesTableModel(null, new String[]{"Nazwa", "Rozszerzenie", "Wielkość", "Data mod.", "Atrybuty"}));
		rightTable.getColumn("Nazwa").setCellRenderer(new FileNameCellRenderer());
		rightTable.setShowGrid(false);
		rightTable.addMouseListener(tableMouseListener);
		//otwieranie folderu - enter
		rightTable.getInputMap().put(KeyStroke.getKeyStroke("ENTER"), "EnterPressed");
		rightTable.getActionMap().put("EnterPressed", enterPressed);
		//przeliczanie rozmiaru katalogu
		rightTable.getInputMap().put(KeyStroke.getKeyStroke("SPACE"), "SpacePressed");
		rightTable.getActionMap().put("SpacePressed", spacePressed);
		
		scrollPaneRight.setViewportView(rightTable);
		
		JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, panelLeft, panelRight);
		splitPane.setResizeWeight(0.5);
		frame.getContentPane().add(splitPane);
		frame.setVisible(true);
	}
	//TODO ew.rozszerzenie JTable (konieczne ze wzgledu na usuniecie odstepow) i dodanie tej motody do klasy
	public void showDir(String address, JTable table) {
		IFile root = FileSystemFactory.getElement(address);
		if (root instanceof IDirectory) {
			List<IFile> files = null;
			try {
				files = ( (IDirectory) root ).listFiles();
			} catch (UnsupportedProtocol e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			((FilesTableModel)table.getModel()).setData(files);
		} else {
			//folder fo nothing here
		}
	}
	
	@SuppressWarnings("serial")
	private class GoToAddressActionLeft extends AbstractAction {
		public void actionPerformed(ActionEvent e) {			//== jest celowe i tak pewnie lepiej zrobic dwie osobne akcje
				String address = addrTextFLeft.getText();
				showDir(address, leftTable);
			}
		}
	
	@SuppressWarnings("serial")
	private class GoToAddressActionRight extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			String address = addrTextFRight.getText();
			showDir(address, rightTable);
			
		}
		
		
	}
	
	private class TableMouseListener extends MouseAdapter {

		@Override
		public void mouseClicked(MouseEvent me) {			//ew. odpalanie innego zdarzenia z tego
			if (me.getClickCount() == 2) {
				doOpenFileAction();
			}
			
		}		
	}
	
	@SuppressWarnings("serial")
	private class EnterPressedAction extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent e) {
			doOpenFileAction();
			
		}
		
	}
	private void doOpenFileAction() {
			int rowIndex = rightTable.getSelectedRow();
			IFile file = ( (FilesTableModel)rightTable.getModel() ).getRow(rowIndex);
			if (file instanceof IDirectory) {		//wyswietlenie zawartości katalogu w w tabeli
				try {
					( (FilesTableModel)rightTable.getModel() ).setData( ( (IDirectory) file ).listFiles() );
					addrTextFRight.setText(file.getPath());
				} catch (UnsupportedProtocol e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			} else {								//podglad pliku
				
			}
			System.out.println(file);
	}
	
	private class SpacePressedAction extends AbstractAction {

		@Override
		public void actionPerformed(ActionEvent e) {
			int row = rightTable.getSelectedRow();
			IFile file = ( (FilesTableModel) rightTable.getModel() ).getRow(row);
			if (file instanceof IDirectory) {
				( (IDirectory) file ).calcDirSize();
			}
		}
		
	}
	
	
	//TODO
	//do obslugi wszystkich zdarzen wystarczy jedna klasa, podmianie bedzie ulegac jedynie 
	//obiekt operacji w roznych instancjach
	//TODO pewnie można to zrobic pewnie bez osobnych akcji dla kazdej z tabel,
	//zdarzenia można rozróżnić na podstawie danych obiektu ActionEvent
	@SuppressWarnings("serial")
	private class DeletingAction extends AbstractAction {
		
		DeleteOperation delOp = null;					 

		@Override
		public void actionPerformed(ActionEvent arg0) {
			//pobranie zaznaczonych plikow
			int [] selectedRows = leftTable.getSelectedRows();
			List<IFile> files = new LinkedList<IFile>();
			IFile selectedFile;
			logger.info("Getting selected for deletion");
			for (int row : selectedRows) {
				selectedFile = ((FilesTableModel)leftTable.getModel()).getRow(row);
				files.add(selectedFile);
			}
			
			
			ProgressFrame progressFrame = new ProgressFrame();
			progressFrame.setVisible(true);
			//TODO chyba najelegantszym rozwiazaniem spelniajacym wymagania projektowe oraz
			//pozwalajacym na operacji nie zajmowac sie pozyskiwaniem zaznaczonych plikow jest 
			//parsowanie xmla i zapisywanie rezultatow parsowania do np. mapy.
			//lub podczas parsowanie ustawianie stosownych operacji dla akcji okreslonych buttonow
			//operacje wtedy powinny byc jako skladowe klas akcji, 
			//wtedy ten konstruktor musi byc wywolywany z uzyciem refleksji
			delOp = new DeleteOperation(files, progressFrame.getProgressBar());
			ExecutorService exs = Executors.newCachedThreadPool();
			exs.execute(delOp);
			
		}
		
		
	}

}
